package cn.lyjuan.first.netty._4_netty_serialize.client;

import cn.lyjuan.base.util.StringUtils;
import cn.lyjuan.first.netty._4_netty_serialize.cst.MessageConst;
import cn.lyjuan.first.netty._4_netty_serialize.msg.MyMessage;
import cn.lyjuan.first.netty._4_netty_serialize.msg.codec.MessageCodec;
import cn.lyjuan.first.netty._4_netty_serialize.server.Server;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;

public class Client
{
    private static Logger log = LogManager.getLogger(Client.class);


    public static void main(String[] args) throws InterruptedException
    {
        Bootstrap strap = new Bootstrap();
        NioEventLoopGroup group = new NioEventLoopGroup();

        try
        {
            start(strap, group);
        } finally
        {
            if (null != group && !group.isShutdown())
                group.shutdownGracefully();
        }
    }

    private static void start(Bootstrap strap, NioEventLoopGroup group) throws InterruptedException
    {
        strap.group(group);
        ChannelFuture future = strap.channel(NioSocketChannel.class)
                .handler(new ChannelInitializer<SocketChannel>()
                {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception
                    {
                        ch.pipeline().addLast(new MessageCodec());
                        ch.pipeline().addLast(new ClientHandler());
                    }
                })
                .connect(new InetSocketAddress("localhost", Server.PORT));

        future.addListener(listener).sync();

        System.out.println("client connect successful");

        future.channel().closeFuture().sync();
    }

    private static ChannelFutureListener listener = new ChannelFutureListener()
    {
        @Override
        public void operationComplete(ChannelFuture future) throws Exception
        {
            if (!future.isSuccess()) return;

            Thread inputRun = new Thread(new InputRun(future));
            inputRun.setDaemon(true);
            inputRun.start();

            if (log.isDebugEnabled())
                log.debug("client start input thread");
        }
    };

    private static class InputRun implements Runnable
    {
        private ChannelFuture future;

        public InputRun(ChannelFuture future)
        {
            this.future = future;
        }

        @Override
        public void run()
        {
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

            try
            {
                while (true)
                {
                    input(in, future.channel());
                }
            } catch (Throwable t)
            {

            } finally
            {
                try
                {
                    in.close();
                } catch (IOException e)
                {
                }
            }
        }
    }

    private static void input(BufferedReader in, Channel chl) throws IOException
    {
        System.out.println("input command");
        String line = in.readLine();
        if (StringUtils.isNull(line)) return;
        line = line.trim();

        String head = null;
        String data = null;

        if (line.matches("^close$"))// close关闭
            chl.close();
        else if (line.matches("^hello$"))// 发送 hello消息
        {
            head = MessageConst.HEAD_HELLO;
            data = "hello";
        } else if (line.startsWith("msg "))// 发送消息，后跟消息内容
        {
            line = line.substring(4);
            if (StringUtils.isNull(line))
            {
                System.out.println("invalid message context");
                return;
            }

            head = MessageConst.HEAD_MSG;
            data = line;
        } else
        {
            System.out.println("invalid command");
            return;
        }

        if (StringUtils.isNull(data))
            return;

        // 发送
        MyMessage msg = new MyMessage(head, data, MessageConst.FOOT);
        chl.writeAndFlush(msg);
    }
}
